home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1997 December
/
MACPOWER-1997-12.ISO.7z
/
MACPOWER-1997-12.ISO
/
AMUG
/
PROGRAMMING
/
Raven 1.2.sit
/
Raven 1.2
/
Source
/
Foundation
/
Common
/
ZStackCrawl.cpp
< prev
next >
Wrap
Text File
|
1997-06-21
|
9KB
|
334 lines
/*
* File: ZStackCrawl.h
* Summary: Stack crawl class based on the class in the OpenDoc utilities.
* Written by: Jesse Jones
*
* Copyright ゥ 1997 Jesse Jones.
* For conditions of distribution and use, see copyright notice in ZTypes.h
*
* Change History (most recent first):
*
* <5> 5/24/97 JDJ Turned on scheduling.
* <4> 3/28/97 JDJ Ctor stops crawling if get a bogus nextStackFrame.
* <3> 2/28/97 JDJ Added a bulleted comment to GetMem.
* <2> 2/27/97 JDJ Removed PPCToolLibs stubs.
* <1> 2/02/97 JDJ Created.
*/
#include <ZStackCrawl.h>
#include <Errors.h>
#include <Files.h>
#include <LowMem.h>
#include <Setjmp.h>
#include <Stdio.h>
#include <Unmangler.h>
#include <ZDebug.h>
#include <ZNubEmbeddedSymbols.h>
#pragma peephole on
#pragma global_optimizer on
#pragma auto_inline on
#pragma scheduling 603
#if powerc
#pragma optimization_level 4
#endif
//==============================================================================
// Stack-crawl types & constants
//==============================================================================
struct LinkAreaPPC {
void* backChain;
void* savedCR;
void* savedLR;
void* reserved;
void* savedTOC;
};
struct LinkArea68k {
void* backChain;
void* returnAddress;
};
union LinkArea {
LinkAreaPPC fPPC;
LinkArea68k f68k;
};
const size_t kMagicA6 = 0xFFFFFFFF; // Signals 68k->PPC switch
const size_t kPPCInstrLen = 4; // Gotta love them RISCs
//==============================================================================
// Locating Stack Pointer
//==============================================================================
#if GENERATING68K
#pragma parameter __D0 GetA6()
extern void* GetA6() = 0x200E; // MOVE.L A6,D0
#elif GENERATINGPOWERPC
#ifdef __MWERKS__
#if __MWERKS__ >= 8
asm static void* GetSP( ) {
mr r3,SP
blr
}
#else
const long kjmp_bufStackFrameIndex = 3; // For CW8 and earlier, not CW9
#endif
#elif defined(__MRC__)
const long kjmp_bufStackFrameIndex = 2; // For MRC
#else
#error "Don't know offset of SP in jmp_buf for this compiler"
#endif
#else
#error "What the hell kinda CPU is this?"
#endif
// ===================================================================================
// class StackID
// This is just a cookie: it's only used to provide some type safety in the interface.
// ===================================================================================
class StackID {
};
// ===================================================================================
// Internal Functions
// ===================================================================================
//---------------------------------------------------------------
//
// GetMem
//
//---------------------------------------------------------------
static OSErr GetMem(void* loc, ULongWord size, void* buffer, va_list args )
{
#pragma unused(args)
// Try to get away without a CPU exception handler by sanity checking:
// ・・・ハThis test does not work when virtual memory is on (which
// ・・・ハmeans the stack crawl has hex addresses instead of names).
if (loc < &SystemZone()->heapData || (void*) loc > LMGetBufPtr()
|| (void*) ((size_t) loc+size) > LMGetBufPtr())
return -1;
else {
BlockMoveData(loc, buffer, size);
return noErr;
}
}
#pragma mark -
// ===================================================================================
// class TStackCrawl
// ===================================================================================
//---------------------------------------------------------------
//
// TStackCrawl::~TStackCrawl
//
//---------------------------------------------------------------
TStackCrawl::~TStackCrawl()
{
}
//---------------------------------------------------------------
//
// TStackCrawl::TStackCrawl
//
//---------------------------------------------------------------
TStackCrawl::TStackCrawl(ulong startFrame, ulong numFrames)
{
ASSERT(startFrame < 16*1024L*1024L);
ASSERT(numFrames > 0);
if (numFrames > kMaxFrames)
numFrames = kMaxFrames;
const void* stackTop;
// Skanky ways to read the CPU registers:
#if GENERATING68K
stackTop = GetA6();
#elif GENERATINGPOWERPC
#if defined(__MWERKS__) && __MWERKS__ >= 8
stackTop = GetSP();
#else
{
jmp_buf regs;
(void) setjmp(regs);
stackTop = regs[kjmp_bufStackFrameIndex];
}
#endif
#endif
const LinkArea* stackFrame = (LinkArea*) stackTop;
const LinkArea* lastStackFrame = nil;
bool isNative = GENERATINGPOWERPC;
const void* pc = nil;
// Crawl up the stack:
ulong nFrames = 0;
ulong endAt = startFrame + numFrames - 1;
while (stackFrame != nil && stackFrame > lastStackFrame && nFrames <= endAt) {
const LinkArea *nextStackFrame;
#if GENERATINGPOWERPC
if (!isNative) {
nextStackFrame = (LinkArea*) stackFrame->f68k.backChain;
if ((char*) nextStackFrame >= LMGetCurStackBase())
break;
else if (((size_t*) nextStackFrame)[-1] == kMagicA6) { // 68k->PPC switch
isNative = true;
stackFrame = nextStackFrame; // Skip switch frame
} else
pc = stackFrame->f68k.returnAddress;
}
if (isNative) {
nextStackFrame = (const LinkArea*) stackFrame->fPPC.backChain;
if ((char*) nextStackFrame >= LMGetCurStackBase())
break;
else if ((ulong) nextStackFrame & 1) { // PPC->68k switch
nextStackFrame = (LinkArea*) ((size_t)nextStackFrame -1);
isNative = false;
pc = nextStackFrame->f68k.returnAddress;
nextStackFrame = (const LinkArea*) nextStackFrame->f68k.backChain;
} else {
pc = (void*) ((size_t) nextStackFrame->fPPC.savedLR - kPPCInstrLen);
}
}
#else
nextStackFrame = (LinkArea*) stackFrame->f68k.backChain;
pc = stackFrame->f68k.returnAddress;
#endif
// If we've reached startFrame record the PC value in our list.
if (nFrames >= startFrame)
mFrame[nFrames - startFrame] = (const void*) ((size_t) pc | isNative);
// Advance to next frame:
lastStackFrame = stackFrame;
stackFrame = (LinkArea*) nextStackFrame;
nFrames++;
// Stop if we've hit the base of the stack:
size_t postFrame = (size_t)stackFrame + (isNative ? sizeof(LinkAreaPPC)
: sizeof(LinkArea68k));
if (postFrame >= (size_t) LMGetCurStackBase())
break;
}
if (nFrames > startFrame)
mNumFrames = nFrames - startFrame;
else
mNumFrames = 0; // can happen if allocate blocks within DumpLeaks
}
//---------------------------------------------------------------
//
// TStackCrawl::GetFrame (ulong)
//
//---------------------------------------------------------------
SStackFrame TStackCrawl::GetFrame(ulong index) const
{
ASSERT(index < 16*1024L*1024L);
ASSERT(index < mNumFrames);
size_t pc = (size_t) mFrame[index] & ~1;
bool native = (bool) ((size_t) mFrame[index] & 1);
return TStackCrawl::GetFrame(pc, native);
}
//---------------------------------------------------------------
//
// TStackCrawl::GetID
//
//---------------------------------------------------------------
StackFrameID TStackCrawl::GetID(ulong index) const
{
ASSERT(index < 16*1024L*1024L);
ASSERT(index < mNumFrames);
StackFrameID id = (StackFrameID) mFrame[index];
return id;
}
//---------------------------------------------------------------
//
// TStackCrawl::GetFrame (StackFrameID) [static]
//
//---------------------------------------------------------------
SStackFrame TStackCrawl::GetFrame(StackFrameID id)
{
ASSERT(id != nil);
size_t pc = (size_t) id & ~1;
bool native = (bool) ((size_t) id & 1);
return TStackCrawl::GetFrame(pc, native);
}
//---------------------------------------------------------------
//
// TStackCrawl::GetCaller [static]
//
//---------------------------------------------------------------
SStackFrame TStackCrawl::GetCaller()
{
TStackCrawl crawl(2, 1);
return crawl.GetFrame(0);
}
//---------------------------------------------------------------
//
// TStackCrawl::GetFrame (size_t, bool) [static]
//
//---------------------------------------------------------------
SStackFrame TStackCrawl::GetFrame(size_t pc, bool native)
{
size_t begin, end;
OSErr err;
char symbol[256];
if (native)
#if GENERATINGPOWERPC
err = LookupPowerPCSym(pc, symbol, &begin, &end, &GetMem);
#else
err = 12345;
#endif
else
err = Lookup68KSym(pc, symbol, &begin, &end, &GetMem);
char fnName[256];
if (err == noErr && symbol[0] != 0)
unmangle(fnName, &symbol[1+(symbol[1] == '.')], 255); // For some reason the traceback names seem to start with "."
else
sprintf(fnName,"%08p (%s)", pc, native ? "PPC" : "68k");
SStackFrame frame;
frame.name = fnName;
frame.start = (const void*) begin;
frame.offset = pc - begin;
frame.native = native;
return frame;
}